<!DOCTYPE html>
<html lang="zh">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>在线运行.vue文件</title>
	<script src="./js/vue.min.js" type="text/javascript" charset="utf-8"></script>
	<style type="text/css">
		* {
			margin: 0;
			padding: 0;
		}
		ul{
			list-style: none;
		}
		html, body,#app {
			width: 100%;
			height: 100%;
		}
		#app {
			display: flex;
		}
		.edit {
			flex: 1;
			display: flex;
			flex-direction: column;
			height: 100%;
		}
		.edit .btns {
			height: 60px;
			background-color: #ccc;
			padding-left: 50px;
			line-height: 60px;
		}
		.edit .btns button {
			padding: 10px 20px;
			border: 1px solid #446;
			border-radius: 5px;
			margin-right: 15px;
		}
		.edit .input {
			flex: 1;
			border: none;
			padding-left: 10px;
			padding-top: 10px;
			font-size: 18px;
		}
		.show {
			flex: 1;
			padding: 10px;
		}
	</style>
</head>
<body>
	<div id="app">
		<edit-view></edit-view>
		<edit-show></edit-show>
	</div>
	<script type="text/javascript">
		const Bus = new Vue();
		Vue.component('edit-view', {
			template: `
				<div class="edit">
					<div class="btns">
						<button @click="run">运行</button>
						<button @click="clear">清空</button>
					</div>
					<textarea class="input" :value="code" @input="handleInput"></textarea>
				</div>
			`,
			data() {
				return {
					code: '',
				}
			},
			methods: {
				run() {
					Bus.$emit('codeRun', this.code)
				},
				clear() {
					this.code = '';
				},
				handleInput(e) {
					this.code = e.target.value;
				}
			}
		});
		
		Vue.component('edit-show', {
			props: {
				code: {
					type: String,
					default: ''
				}
			},
			template: `
				<div class="show">
					<h2>此处显示组件结果</h2>
					<div class="show-box" ref="showBox"></div>
				</div>
			`,
			data() {
				return {
					code: '',
				}
			},
			mounted() {
				Bus.$on('codeRun', (code) => {
					this.renderCom(code);
				});
			},
			methods: {
				getCodeStr(type, code) {
					// 匹配开始标签
					let reg = new RegExp(`<${type}[^>]*>`);
					let matchs= code.match(reg);
					if(matchs){
						let tag = matchs[0];
						return code.slice(code.indexOf(tag) + tag.length, code.lastIndexOf(`</${type}>`));
					}
					return '';
				},
				renderCom(code) {
					if(!code) return;
					const template = this.getCodeStr('template', code);
					
					// console.log(template, 'template')
					const script = this.getCodeStr('script', code).replace('export default', 'return');
					let component = {};
					if(script) {
						const fn = new Function(script);
						component = fn();
					}
					if(template) {
						component.template = template;
					}
					const instance = new (this.$options._base.extend(component));
					this.$refs.showBox.appendChild(instance.$mount().$el);
					const style = this.getCodeStr('style', code);
					if(style) {
						let styleDom = document.createElement('style')
						styleDom.innerHTML = style;
						styleDom.setAttribute('type', 'text/css');
						document.head.appendChild(styleDom);
					}
				}
			}
		});
		
		const vm = new Vue({
			el: '#app',
			data() {
				return {}
			},
			methods: {}
		})
	</script>
</body>
</html>